﻿using System;
using System.Linq;
using System.ServiceModel;
using System.Data.SqlClient;
using Streaming_Service.Crawler;
using Streaming_Service.Media;
using Streaming_Service.User;

namespace Streaming_Service {
    using System.Collections.Generic;
    using System.IO;

    using Streaming_Service.Enum;
    using Streaming_Service.FileTransfer;
    using Streaming_Service.SQL_Ting;

    public class RentIt11 : IRentIt {
        public static string BaseUrl = "";

        public UserSession Login(string email, string password) {
            if (UserRegex.ValidEmail(email) && UserRegex.ValidPassword(password)) {
                var sh = DBHandler.GetHandler();
                try {
                    sh.Connect();
                    return UserQueries.Login(email, password, sh);
                } finally {
                    sh.Close();
                }
            }
            return null;
        }

        public void Logout(UserSession session) {
            var sh = DBHandler.GetHandler();
            sh.Connect();
            var properSession = UserQueries.VerifyUserSession(session, sh);
            if (UserFunc.IsUser(session, properSession)) {
                UserQueries.Logout(session, sh);
            }
            sh.Close();
        }

        public UserReturnCode CreateAccount(string name, string password, string email, DateTime birthday) {
            var sh = DBHandler.GetHandler();
            try {
                sh.Connect();
                return UserQueries.CreateAccount(name, password, email, birthday, sh);
            } finally {
                sh.Close();
            }
        }

        public UserReturnCode UpdateAccount(UserSession user, string newPassword, string newEmail, DateTime? newBirthday) {
            var sh = DBHandler.GetHandler();
            try {
                sh.Connect();
                var properSession = UserQueries.VerifyUserSession(user, sh);
                if (UserFunc.IsUser(user, properSession)) {
                    return UserQueries.UpdateAccount(
                        properSession.UserId, newPassword, newEmail, newBirthday, XBool.Ignore, sh);
                }
                return UserReturnCode.InvalidSession;
            }finally {
                sh.Close();
            }
        }

        public UserReturnCode DeleteAccount(UserSession user, string password) {
            var sh = DBHandler.GetHandler();
            try {
                sh.Connect();
                var properSession = UserQueries.VerifyUserSession(user, sh);
                if (UserFunc.IsUser(user, properSession)) {
                    return UserQueries.DeleteAccount(properSession.UserId, password, false, sh);
                }
                return UserReturnCode.InvalidSession;
            } finally {
                sh.Close();
            }
        }

        public UserReturnCode AdminUpdateAccount(UserSession admin, int userId, string newPassword, string newEmail, DateTime? newBirthday, XBool isAdmin) {
            var sh = DBHandler.GetHandler();
            try {
                sh.Connect();
                var properSession = UserQueries.VerifyUserSession(admin, sh);
                if (UserFunc.IsAdmin(admin, properSession)) {
                    return UserQueries.UpdateAccount(
                        userId, newPassword, newEmail, newBirthday, isAdmin, sh);
                }
                return UserReturnCode.AdminRequired;
            } finally {
                sh.Close();
            }
        }

        public UserReturnCode AdminDeleteAccount(UserSession admin, int userId) {
            var sh = DBHandler.GetHandler();
            try {
                sh.Connect();
                var properSession = UserQueries.VerifyUserSession(admin, sh);
                if (UserFunc.IsAdmin(admin, properSession)) {
                    return UserQueries.DeleteAccount(userId, null, true, sh);
                }
                return UserReturnCode.AdminRequired;
            } finally {
                sh.Close();
            }
        }

        public List<UserEntry> ListUsers() {
            var sh = DBHandler.GetHandler();
            try {
                sh.Connect();
                return  UserQueries.ListUsers(sh);
            } finally {
                sh.Close();
            }
        }

        public List<UserEntry> ListOnlineUsers(int inactivityCutOff) {
            var sh = DBHandler.GetHandler();
            try {
                sh.Connect();
                return UserQueries.ListOnlineUsers(inactivityCutOff, sh);
            } finally {
                sh.Close();
            }
        }

        public UserEntry GetUserInfo(int userId) {
            var sh = DBHandler.GetHandler();
            try {
                sh.Connect();
                return UserQueries.GetUserInfo(userId, sh);
            } finally {
                sh.Close();
            }
        }

        public UserEntry GetUserInfoByEmail(string email) {
            var sh = DBHandler.GetHandler();
            try {
                sh.Connect();
                return UserQueries.GetUserInfo(email, sh);
            } finally {
                sh.Close();
            }
        }

        public string GetActivationCode(int userId) {
            var sh = DBHandler.GetHandler();
            try {
                sh.Connect();
                return UserQueries.GetActivationCode(userId, sh);
            } finally {
                sh.Close();
            }
        }

        public bool ActivateAccount(int userId, string code) {
            if (!string.IsNullOrEmpty(code)) {
                var sh = DBHandler.GetHandler();
                try {
                    sh.Connect();
                    return UserQueries.ActivateAccount(userId, code, sh);
                } finally {
                    sh.Close();
                }
            }
            return false;
        }

        public bool IsAccountActivated(int userId) {
            var sh = DBHandler.GetHandler();
            try {
                sh.Connect();
                return !UserQueries.ActivationRequired(userId, sh);
            } finally {
                sh.Close();
            }
        }

        public List<MovieSearchEntry> ListAllSearches(int userid, int numResults) {
            var sh = DBHandler.GetHandler();
            try {
                sh.Connect();
                return MovieQueries.ListAllSearches(userid, numResults, sh);
            } finally {
                sh.Close();
            }
        }

        public bool Rent(int movieId, UserSession session, bool hd) {
            var sh = DBHandler.GetHandler();
            try {
                sh.Connect();
                var properSession = UserQueries.VerifyUserSession(session, sh);
                if (UserFunc.IsUser(session, properSession)) {
                    return RentQueries.RentMovie(session.UserId, movieId, hd, sh);
                }
                return false;
            } finally {
                sh.Close();
            }
        }

        public bool ActiveRent(int movieId, UserSession user, bool hd) {
            var sh = DBHandler.GetHandler();
            try {
                sh.Connect();
                var properSession = UserQueries.VerifyUserSession(user, sh);
                if (UserFunc.IsUser(user, properSession)) {
                    return RentQueries.ActiveRent(user.UserId, movieId, hd, sh);
                }
                return false;
            } finally {
                sh.Close();
            } 
        }

        public List<String> ListMovieLanguages() {
            var sh = DBHandler.GetHandler();
            try {
                sh.Connect();
                return MovieQueries.MovieLanguages(sh);
            } finally {
                sh.Close();
            }
        }

        public List<MovieEntry> SearchMovies(MovieSearchEntry searchEntry) {
            var sh = DBHandler.GetHandler();
            try {
                sh.Connect();
                if(!searchEntry.DoNotSaveToSearchHistory) MovieQueries.InsertSearch(searchEntry, sh);
                return MovieQueries.SearchMovies(searchEntry, sh);
            } finally {
                sh.Close();
            }
        }

        public int InsertMovie(UserSession admin, MovieEntry movieEntry) {
            var sh = DBHandler.GetHandler();
            try {
                sh.Connect();
                var properSession = UserQueries.VerifyUserSession(admin, sh);
                if (UserFunc.IsAdmin(admin, properSession)) {
                    return MovieQueries.InsertMovie(movieEntry, sh);
                }
                return -1;
            } finally {
                sh.Close();
            }
        }

        public bool EditMovie(UserSession admin, int movieId, MovieEntry movieEntry) {
            var sh = DBHandler.GetHandler();
            try {
                sh.Connect();
                var properSession = UserQueries.VerifyUserSession(admin, sh);
                if (UserFunc.IsAdmin(admin, properSession)) {
                    return MovieQueries.UpdateMovie(movieId, movieEntry, sh);
                }
                return false;
            } finally {
                sh.Close();
            }
        }

        public bool DeleteMovie(UserSession admin, int movieId) {
            var sh = DBHandler.GetHandler();
            try {
                sh.Connect();
                var properSession = UserQueries.VerifyUserSession(admin, sh);
                if (UserFunc.IsAdmin(admin, properSession)) {
                    return MovieQueries.DeleteMovie(movieId, sh);
                }
                return false;
            } finally {
                sh.Close();
            }
        }

        public UploadFileResponse UploadMovieFile(UploadFileInfo uploadFileInfo) {
            var admin = uploadFileInfo.Admin;
            var movieId = uploadFileInfo.MovieId;
            var sh = DBHandler.GetHandler();
            try {
                sh.Connect();
                var properSession = UserQueries.VerifyUserSession(admin, sh);
                if (UserFunc.IsAdmin(admin, properSession)) {
                    if (MovieQueries.MovieExists(movieId, sh)) {
                        if (FileTransferHelper.ReceiveUpload(uploadFileInfo)) {
                            return new UploadFileResponse(MediaFunc.MoveMovieFile(movieId, uploadFileInfo));
                        }
                    }
                }
                return new UploadFileResponse(false);
            } finally {
                sh.Close();
            }
        }

        public UploadFileResponse UploadMovieThumb(UploadFileInfo uploadFileInfo) {
            var admin = uploadFileInfo.Admin;
            var movieId = uploadFileInfo.MovieId;
            var sh = DBHandler.GetHandler();
            try {
                sh.Connect();
                var properSession = UserQueries.VerifyUserSession(admin, sh);
                if (UserFunc.IsAdmin(admin, properSession)) {
                    if (MovieQueries.MovieExists(movieId, sh)) {
                        if (FileTransferHelper.ReceiveUpload(uploadFileInfo)) {
                            return new UploadFileResponse(MediaFunc.MoveThumbFile(movieId, uploadFileInfo));
                        }
                    }
                }
                return new UploadFileResponse(false);
            } finally {
                sh.Close();
            }
        }

        public HashSet<string> AllowedMovieFileExtensions() {
            return MediaFunc.movieFileExtensions;
        }

        public HashSet<string> AllowedThumbFileExtensions() {
            return MediaFunc.thumbFileExtensions;
        }

        public MovieEntry MovieInfo(int movieId) {
            var sh = DBHandler.GetHandler();
            try {
                sh.Connect();
                return MovieQueries.GetMovie(movieId, sh);
            } finally {
                sh.Close();
            }
        }

        public List<MovieEntry> ListMovies() {
            var sh = DBHandler.GetHandler();
            try {
                sh.Connect();
                return MovieQueries.ListMovies(sh);
            } finally {
                sh.Close();
            }
        }

        public int MovieCount() {
            var sh = DBHandler.GetHandler();
            try {
                sh.Connect();
                return MovieQueries.MovieCount(sh);
            } finally {
                sh.Close();
            }
        }

        public bool AddGenre(UserSession admin, string genre) {
            var sh = DBHandler.GetHandler();
            try {
                sh.Connect();
                var properSession = UserQueries.VerifyUserSession(admin, sh);
                if (UserFunc.IsAdmin(admin, properSession)) {
                    return GenreQueries.AddGenre(genre, sh);
                }
                return false;
            } finally {
                sh.Close();
            }
        }

        public bool GenreExists(string genre) {
            var sh = DBHandler.GetHandler();
            try {
                sh.Connect();
                return GenreQueries.GenreExists(genre, sh);
            }finally {
                sh.Close();
            }
        }

        public bool RemoveGenre(UserSession admin, int genreId) {
            var sh = DBHandler.GetHandler();
            try {
                sh.Connect();
                var properSession = UserQueries.VerifyUserSession(admin, sh);
                if (properSession != null && properSession.IsAdmin) {
                    return GenreQueries.DeleteGenre(genreId, sh);
                }
                return false;
            }finally {
                sh.Close();
            }
        }

        public bool RenameGenre(UserSession admin, int genreId, string newName) {
            var sh = DBHandler.GetHandler();
            try {
                sh.Connect();
                var properSession = UserQueries.VerifyUserSession(admin, sh);
                if (properSession != null && properSession.IsAdmin) {
                    return GenreQueries.RenameGenre(genreId, newName, sh);
                }
                return false;
            }finally {
                sh.Close();
            }
        }

        public bool AddMovieGenre(UserSession admin, int movieId, int genreId) {
            var sh = DBHandler.GetHandler();
            try {
                sh.Connect();
                var properSession = UserQueries.VerifyUserSession(admin, sh);
                if (properSession != null && properSession.IsAdmin) {
                    return GenreQueries.AddMovieGenre(movieId, genreId, sh);
                }
                return false;
            }finally {
                sh.Close();
            }
        }

        public bool RemoveMovieGenre(UserSession admin, int movieId, int genreId) {
            var sh = DBHandler.GetHandler();
            try {
                sh.Connect();
                var properSession = UserQueries.VerifyUserSession(admin, sh);
                if (properSession != null && properSession.IsAdmin) {
                    return GenreQueries.DeleteMovieGenre(movieId, genreId, sh);
                }
                return false;
            } finally {
                sh.Close();
            }
        }

        public List<GenreEntry> ListGenres() {
            var sh = DBHandler.GetHandler();
            try {
                sh.Connect();
                return GenreQueries.ListGenres(sh);
            } finally {
                sh.Close();
            }
        }

        public ImdbMovieEntry GetImdbMovie(string imdbId) {
            return ImdbCrawler.GetMovieInfo(imdbId);
        }

        public bool MovieExists(string title, int year) {
            var sh = DBHandler.GetHandler();
            try {
                sh.Connect();
                return MovieQueries.MovieExists(title, year, sh);
            } finally {
                sh.Close();
            }
        }

        public bool MovieExistsImdb(string imdbId) {
            var sh = DBHandler.GetHandler();
            try {
                sh.Connect();
                return MovieQueries.MovieExistsImdb(imdbId, sh);
            } finally {
                sh.Close();
            }
        }

        public decimal GetSdPrice(MovieEntry movie) {
            var sh = DBHandler.GetHandler();
            try {
                sh.Connect();
                return PricingQueries.GetSdPrice(movie, sh);
            } finally {
                sh.Close();
            }
        }

        public decimal GetHdPrice(MovieEntry movie) {
            var sh = DBHandler.GetHandler();
            try {
                sh.Connect();
                return PricingQueries.GetHdPrice(movie, sh);
            } finally {
                sh.Close();
            }
        }

        public decimal GetSdPriceByMovieId(int movieId) {
            var sh = DBHandler.GetHandler();
            try {
                sh.Connect();
                return PricingQueries.GetSdPrice(movieId, sh);
            } finally {
                sh.Close();
            }
        }

        public decimal GetHdPriceByMovieId(int movieId) {
            var sh = DBHandler.GetHandler();
            try {
                sh.Connect();
                return PricingQueries.GetHdPrice(movieId, sh);
            } finally {
                sh.Close();
            }
        }

        public ParentalGuidance GetParentalGuidance(string toParse) {
            return EnumHelper.GetParentalGuidance(toParse);
        }

        public bool IsTrue(XBool xbool) {
            return EnumHelper.IsTrue(xbool);
        }

        public List<RentSession> UserRents(int userId, bool onlyActive) {
            var sh = DBHandler.GetHandler();
            try {
                sh.Connect();
                return RentQueries.UserRents(userId, onlyActive, sh);
            } finally {
                sh.Close();
            }
        }

        public List<RentSession> UserRentSessions(UserSession user, bool onlyActive) {
            var sh = DBHandler.GetHandler();
            try {
                sh.Connect();
                return RentQueries.UserRentSessions(user, onlyActive, sh);
            } finally {
                sh.Close();
            }
        }

        public bool RateMovie(UserSession user, RatingEntry rating) {
            if (rating == null) return false;
            var sh = DBHandler.GetHandler();
            try {
                sh.Connect();
                var properSession = UserQueries.VerifyUserSession(user, sh);
                if (UserFunc.IsUser(user, properSession)) {
                    return RatingQueries.RateMovie(user, rating.MovieId, rating.Rating, rating.Comment, sh);
                }
                return false;
            }
            finally {
                sh.Close();
            }
        }

        public bool EditRating(UserSession user, RatingEntry rating) {
            if (rating == null) return false;
            var sh = DBHandler.GetHandler();
            try {
                sh.Connect();
                var properSession = UserQueries.VerifyUserSession(user, sh);
                if (UserFunc.IsUser(user, properSession)) {
                    return RatingQueries.EditRating(user, rating.MovieId, rating.Rating, rating.Comment, sh);
                }
                return false;
            } finally {
                sh.Close();
            }
        }

        public bool DeleteRating(UserSession user, int movieId) {
            var sh = DBHandler.GetHandler();
            try {
                sh.Connect();
                var properSession = UserQueries.VerifyUserSession(user, sh);
                if (UserFunc.IsUser(user, properSession)) {
                    return RatingQueries.DeleteRating(user, movieId, sh);
                }
                return false;
            } finally {
                sh.Close();
            }
        }

        public List<RatingEntry> ListRatings() {
            var sh = DBHandler.GetHandler();
            try {
                sh.Connect();
                return RatingQueries.ListRatings(sh);
            } finally {
                sh.Close();
            }
        }

        public List<RatingEntry> ListUserRatings(int userId) {
            var sh = DBHandler.GetHandler();
            try {
                sh.Connect();
                return RatingQueries.UserRatings(userId, sh);
            } finally {
                sh.Close();
            }
        }

        public List<RatingEntry> ListMovieRatings(int movieId) {
            var sh = DBHandler.GetHandler();
            try {
                sh.Connect();
                return RatingQueries.MovieRatings(movieId, sh);
            } finally {
                sh.Close();
            }
        }
    }
}
